package factorytest.iflytek.com.einkiflytekfactorytest.engineerui;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;

import java.math.BigDecimal;

import factorytest.iflytek.com.einkiflytekfactorytest.engineerui.PenCalibActivity;

public class PenCalibTextView extends TextView {
	public static String TAG = PenCalibActivity.TAG;

	public static final int 	CYCLE_RADUS = 25; // pixel;
	public static final int 	TOUCHPOINT_RADUS = 7;

	public static final int 	CYCLE_STOKE_WIDTH = 3;
	public static final int 	CROSS_STOKE_WIDTH = 1;

	public static final int 	TEXT_SIZE = 60;

	private	Paint		mDrawingPaint =  new Paint();
	private	Paint		mTextPaint =  new Paint();
	private int			mTouchX;
	private int 		mTouchY;

	public static final int 	CALIB_POINT_COUNT = 5;
	public static final int 	CALIB_POINT_X_MARGIN = 100;
	public static final int 	CALIB_POINT_Y_MARGIN = 100;
	private boolean				mCaliPointTouched[] = new boolean[CALIB_POINT_COUNT];
	private Point				mCalibPoints[] = new Point[CALIB_POINT_COUNT];
	private Point				mCalibTouchPoints[] = new Point[CALIB_POINT_COUNT];

	private int			mCalibX;
	private int 		mCalibY;
	private int 		mCalibTouchCount = 0;

	private OnClickAllCheckPointCallback checkPointCallback;

//	private Path 		mTouchPath = new Path();
	public PenCalibTextView(Context context) {
//		super(context);
		this(context,null);
	}

	public PenCalibTextView(Context context, AttributeSet attrs) {
//		super(context, attrs);
		this(context,attrs,0);
	}

	public PenCalibTextView(Context context, AttributeSet attrs, int defStyleAttr) {
//		super(context, attrs, defStyleAttr);
		this(context,attrs,defStyleAttr,0);
	}

	public PenCalibTextView(Context arg0, AttributeSet arg1, int arg2, int arg3) {
		super(arg0, arg1, arg2, arg3);
		init();
	}

	public void setCheckPointCallback(OnClickAllCheckPointCallback checkPointCallback) {
		this.checkPointCallback = checkPointCallback;
	}

	private void init() {
//		this.setEinkUpdateMode(EINK_DATA_MODE_DEFAULT, EINK_SHOW_MODE_GL);
		mDrawingPaint.setColor(Color.BLACK);
		mTextPaint.setColor(Color.BLACK);
		mTextPaint.setStyle(Paint.Style.STROKE);
		mTextPaint.setTextSize(TEXT_SIZE);
//		mDrawingPaint.setStyle(Paint.Style.FILL_AND_STROKE);
//		mDrawingPaint.setStrokeWidth(5);
		for(int i = 0; i < mCalibPoints.length; i++) {
			mCalibPoints[i] = new Point();
			mCalibTouchPoints[i] = new Point();
			mCaliPointTouched[i] = false;
		}
		mCalibTouchCount = 0;

		this.addOnLayoutChangeListener( new OnLayoutChangeListener() {

			@Override
			public void onLayoutChange(View v, int left, int top, int right,
					int bottom, int arg5, int arg6, int arg7, int arg8) {
				// init the calib touch points.
				int w = right - left;
				int h = bottom - top;
				Log.d(TAG, "View-onLayoutChange w=" + w + ",h=" + h);

				mCalibPoints[0].x = CALIB_POINT_X_MARGIN;
				mCalibPoints[0].y = CALIB_POINT_Y_MARGIN;

				mCalibPoints[1].x = w - CALIB_POINT_X_MARGIN;
				mCalibPoints[1].y = CALIB_POINT_Y_MARGIN;

				mCalibPoints[2].x = CALIB_POINT_X_MARGIN;
				mCalibPoints[2].y = h - CALIB_POINT_Y_MARGIN;

				mCalibPoints[3].x = w - CALIB_POINT_X_MARGIN;
				mCalibPoints[3].y = h - CALIB_POINT_Y_MARGIN;

				// 20180402,the final is the center point!
				mCalibPoints[4].x = w / 2;
				mCalibPoints[4].y = h / 2;
			}
		});
	}

	private boolean checkAndSetTouchPoint(int x, int y) {
		boolean valid = false;
		for(int i = 0; i < mCalibPoints.length; i++) {
			if( Math.abs(x - mCalibPoints[i].x ) < CYCLE_RADUS
					&& Math.abs(y - mCalibPoints[i].y ) < CYCLE_RADUS) {
				Log.d(TAG, "Touch (" + x + "," + y + ") at Point:" + mCalibPoints[i]);
				mCaliPointTouched[i] = true;
				mCalibTouchPoints[i].x = x;
				mCalibTouchPoints[i].y = y;
				valid = true;
				break;
			}
		}
		if( !valid ) return valid;

		// here,all touch point is calibration,print the info:
		mCalibX = 0;
		mCalibY = 0;
		mCalibTouchCount = 0;
		for(int i = 0; i < mCalibPoints.length; i++) {
			if( mCaliPointTouched[i] ) {
				/**
				 * 20180403: we want the correct value(calib x/y) after calibration.that is
				 * touch-x + Cx = calib-x; touch-y + Cy = calib-y;
				 * touch x/y is the input Motion Event x/y.
				 * so the Cx = calib-x - touch-x;
				 */
				int cx = mCalibPoints[i].x - mCalibTouchPoints[i].x;
				int cy = mCalibPoints[i].y - mCalibTouchPoints[i].y;
				Log.d(TAG, "Calib Point[" + i + "]=" + mCalibPoints[i]
						+ ",Touch Point=" + mCalibTouchPoints[i]
						+ ",cab=" + cx + "," + cy);
				mCalibX += cx;
				mCalibY += cy;
				mCalibTouchCount++;
			} else {
				Log.d(TAG, "No-Calib Point[" + i + "]=" + mCalibPoints[i]);
			}
		}

		if( mCalibTouchCount > 0 ) {
			mCalibX = mCalibX/ mCalibTouchCount;
			mCalibY = mCalibY/ mCalibTouchCount;
		}

		// click all test points
		if( mCalibTouchCount == mCalibPoints.length) {
			Log.d(TAG, "Final Calibration:CX=" + mCalibX + ",CY=" + mCalibY);

			if (checkPointCallback != null) {
				checkPointCallback.onClickAllCheckPointCallback(mCalibX, mCalibY);

			}
		}

		return valid;
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		// 20180402,drop all finger touch.
		if( event.getToolType(0) != MotionEvent.TOOL_TYPE_STYLUS ) {
			return false;
		}

		int action = event.getAction();

		mTouchX = (int) event.getX();
		mTouchY = (int) event.getY();

		Log.d("TOUCH", "X=:" + mTouchY + ",Y=" + mTouchY);
		switch(action) {
		case MotionEvent.ACTION_DOWN:
//			mTouchPath.reset();
//			mDrawCursorHandler.removeMessages(MSG_CLEAR_PATH);
//			mTouchPath.moveTo(x, y);
//			invalidate();
			break;
		case MotionEvent.ACTION_MOVE:
//			mTouchPath.lineTo(x, y);
//			invalidate();
			break;
		case MotionEvent.ACTION_UP:
//			mTouchPath.lineTo(x, y);
//			setAutoClearPath();
			if( checkAndSetTouchPoint(mTouchX, mTouchY) ){
				invalidate();
			}
			break;
		}
		return true;

	}

	private void setAutoClearPath(){
		mDrawCursorHandler.sendEmptyMessageDelayed(MSG_CLEAR_PATH, 2000);
	}

	private static final int MSG_CLEAR_PATH = 100;

	Handler mDrawCursorHandler = new Handler() {
        public void handleMessage(Message msg) {
            // process incoming messages here
            switch (msg.what){
                case MSG_CLEAR_PATH:
//                	mTouchPath.reset();
                	invalidate();
                    break;
            }
        }
	};

	@Override
	protected void onDraw(Canvas canvas) {
		// TODO Auto-generated method stub
		super.onDraw(canvas);
//		canvas.drawPath(mTouchPath, mDrawingPaint);
		drawCalibValue(canvas);
		drawCalibPoints(canvas);
		drawTouchPoints(canvas);

	}

	private void drawCalibPoints(Canvas c) {
		for(int i = 0; i < mCalibPoints.length; i++) {
			drawPoint(c, mCalibPoints[i].x, mCalibPoints[i].y);
		}
	}

	private void drawPoint(Canvas canvas, int x, int y) {
		mDrawingPaint.setStyle(Paint.Style.STROKE);
		mDrawingPaint.setStrokeWidth(CYCLE_STOKE_WIDTH);
		canvas.drawCircle(x, y, CYCLE_RADUS, mDrawingPaint);

		mDrawingPaint.setStyle(Paint.Style.FILL_AND_STROKE);
		mDrawingPaint.setStrokeWidth(CROSS_STOKE_WIDTH);
		canvas.drawLine(x-CYCLE_RADUS, y, x+CYCLE_RADUS, y, mDrawingPaint);
		canvas.drawLine(x, y-CYCLE_RADUS, x, y+CYCLE_RADUS, mDrawingPaint);
	}

	private void drawTouchPoints(Canvas c) {
		for(int i = 0; i < mCalibTouchPoints.length; i++) {
			if( mCaliPointTouched[i] ) {
				drawTouchPoint(c, mCalibTouchPoints[i].x, mCalibTouchPoints[i].y);
			}
		}
	}

	private void drawTouchPoint(Canvas canvas, int x, int y) {
		mDrawingPaint.setStyle(Paint.Style.FILL_AND_STROKE);
		mDrawingPaint.setStrokeWidth(TOUCHPOINT_RADUS);
		canvas.drawPoint(x, y, mDrawingPaint);
	}

	private void drawCalibValue(Canvas canvas) {

		mDrawingPaint.setStyle(Paint.Style.STROKE);
		int tx = mCalibPoints[mCalibTouchPoints.length -1].x;
		int ty = mCalibPoints[mCalibTouchPoints.length -1].y;

		float cx = mCalibX * 1.0f / 0.089f;
		float cy = mCalibY * 1.0f / 0.089f;

		BigDecimal dCX = new BigDecimal(cx);
		BigDecimal dCY = new BigDecimal(cy);
		float fCX = dCX.setScale(2, BigDecimal.ROUND_HALF_UP).floatValue();
		float fCY = dCY.setScale(2, BigDecimal.ROUND_HALF_UP).floatValue();

		canvas.drawText("已测试：" + mCalibTouchCount + " 个点!", tx - 320, ty - 270, mTextPaint);
//		mDrawingPaint.setStyle(Paint.Style.STROKE);
		canvas.drawText("误差 Offset：X = " + Math.abs(fCX) + " , Y = " + Math.abs(fCY), tx - 320, ty - 180, mTextPaint);
		canvas.drawText("允许误差范围: (|X| < 100 & |Y| < 100)", tx - 320, ty - 90, mTextPaint);

	}

	public interface OnClickAllCheckPointCallback {
		void onClickAllCheckPointCallback(int calibX, int calibY);
	}
}
